package v1beta1

import (
	"fmt"
	"time"

	"go.uber.org/zap"
	confv1beta1 "gopkg.openfuyao.cn/bkecommon/cluster/api/v1beta1"
	corev1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/client-go/tools/record"
	"sigs.k8s.io/cluster-api/util/version"

	"gopkg.openfuyao.cn/cluster-api-provider-bke/utils/annotation"
	log "gopkg.openfuyao.cn/cluster-api-provider-bke/utils/log"
)

const (
	ClusterFinalizer = "bkecluster.infrastructure.cluster.x-k8s.io"
)

var (
	// ExpectMinK8sVersion is the minimum kubernetes version supported by the provider
	ExpectMinK8sVersion, _ = version.ParseMajorMinorPatch("v1.27.0")
	// ExpectMaxK8sVersion is the maximum kubernetes version supported by the provider
	ExpectMaxK8sVersion, _ = version.ParseMajorMinorPatch("v1.34.2")
)

// BKELogger is a wrapper of zap.SugaredLogger and record.EventRecorder
// +kubebuilder:object:generate:=false
type BKELogger struct {
	NormalLogger *zap.SugaredLogger
	Recorder     record.EventRecorder
	EventBinder  runtime.Object
}

func NewBKELogger(log *zap.SugaredLogger, recorder record.EventRecorder, binder runtime.Object) *BKELogger {
	return &BKELogger{
		NormalLogger: log,
		Recorder:     recorder,
		EventBinder:  binder,
	}
}

func (logger *BKELogger) Info(reason, msg string, args ...interface{}) {
	tameStamp := time.Now().Unix()
	msg = fmt.Sprintf("(%d) %s", tameStamp, msg)
	logger.Recorder.AnnotatedEventf(logger.EventBinder, annotation.BKENormalEventAnnotation(), corev1.EventTypeNormal, reason, msg, args...)
	if logger.NormalLogger != nil {
		logger.NormalLogger.Infof(msg, args...)
		return
	}
	log.Infof(msg, args...)
}

func (logger *BKELogger) Error(reason, msg string, args ...interface{}) {
	tameStamp := time.Now().Unix()
	msg = fmt.Sprintf("(%d) %s", tameStamp, msg)
	logger.Recorder.AnnotatedEventf(logger.EventBinder, annotation.BKENormalEventAnnotation(), corev1.EventTypeWarning, reason, msg, args...)
	if logger.NormalLogger != nil {
		logger.NormalLogger.Errorf(msg, args...)
		return
	}
	log.Errorf(msg, args...)
}

func (logger *BKELogger) Warn(reason, msg string, args ...interface{}) {
	tameStamp := time.Now().Unix()
	msg = fmt.Sprintf("(%d) %s", tameStamp, msg)
	logger.Recorder.AnnotatedEventf(logger.EventBinder, annotation.BKENormalEventAnnotation(), corev1.EventTypeWarning, reason, msg, args...)
	if logger.NormalLogger != nil {
		logger.NormalLogger.Warnf(msg, args...)
		return
	}
	log.Warnf(msg, args...)
}

func (logger *BKELogger) Finish(reason, msg string, args ...interface{}) {
	tameStamp := time.Now().Unix()
	msg = fmt.Sprintf("(%d) %s", tameStamp, msg)
	logger.Recorder.AnnotatedEventf(logger.EventBinder, annotation.BKEFinishEventAnnotation(), corev1.EventTypeNormal, reason, msg, args...)
	if logger.NormalLogger != nil {
		logger.NormalLogger.Infof(msg, args...)
		return
	}
	log.Infof(msg, args...)
}

func (logger *BKELogger) Debug(msg string, args ...interface{}) {
	logger.NormalLogger.Debugf(msg, args...)
}

// condition type constants
const (
	ControlPlaneEndPointSetCondition confv1beta1.ClusterConditionType = "ControlPlaneEndPointSet"
	TargetClusterReadyCondition      confv1beta1.ClusterConditionType = "TargetClusterReady"
	TargetClusterBootCondition       confv1beta1.ClusterConditionType = "TargetClusterBoot"
	ClusterAddonCondition            confv1beta1.ClusterConditionType = "Addon"
	NodesInfoCondition               confv1beta1.ClusterConditionType = "NodesInfo"
	BKEAgentCondition                confv1beta1.ClusterConditionType = "BKEAgent"
	LoadBalancerCondition            confv1beta1.ClusterConditionType = "LoadBalancer"
	NodesEnvCondition                confv1beta1.ClusterConditionType = "NodesEnv"
	ClusterAPIObjCondition           confv1beta1.ClusterConditionType = "ClusterAPIObj"
	SwitchBKEAgentCondition          confv1beta1.ClusterConditionType = "SwitchBKEAgent"
	ControlPlaneInitializedCondition confv1beta1.ClusterConditionType = "ControlPlaneInitialized"
	BKEConfigCondition               confv1beta1.ClusterConditionType = "BKEConfig"
	ClusterHealthyStateCondition     confv1beta1.ClusterConditionType = "ClusterHealthyState"

	BootstrapSucceededCondition = "BootstrapSucceeded"

	// for bocloud cluster
	BocloudClusterDataBackupCondition             confv1beta1.ClusterConditionType = "BocloudClusterDataBackup"
	BocloudClusterMasterCertDistributionCondition confv1beta1.ClusterConditionType = "BocloudClusterMasterCertDistribution"
	BocloudClusterWorkerCertDistributionCondition confv1beta1.ClusterConditionType = "BocloudClusterWorkerCertDistribution"
	BocloudClusterEnvInitCondition                confv1beta1.ClusterConditionType = "BocloudClusterEnvInit"
	TypeOfManagementClusterGuessCondition         confv1beta1.ClusterConditionType = "TypeOfManagementClusterGuess"

	InternalSpecChangeCondition confv1beta1.ClusterConditionType = "InternalSpecChange"
)

const (
	InitControlPlane     confv1beta1.BKEClusterPhase = "InitControlPlane"
	JoinControlPlane     confv1beta1.BKEClusterPhase = "JoinControlPlane"
	JoinWorker           confv1beta1.BKEClusterPhase = "JoinWorker"
	FakeInitControlPlane confv1beta1.BKEClusterPhase = "FakeInitControlPlan"
	FakeJoinControlPlane confv1beta1.BKEClusterPhase = "FakeJoinControlPlan"
	FakeJoinWorker       confv1beta1.BKEClusterPhase = "FakeJoinWorker"
	FailedBootstrapNode  confv1beta1.BKEClusterPhase = "FailedBootstrapNode"
	UpgradeControlPlane  confv1beta1.BKEClusterPhase = "UpgradeControlPlane"
	UpgradeWorker        confv1beta1.BKEClusterPhase = "UpgradeWorker"
	UpgradeEtcd          confv1beta1.BKEClusterPhase = "UpgradeEtcd"
	ClusterReadyOld      confv1beta1.BKEClusterPhase = "ClusterReady"
	Scale                confv1beta1.BKEClusterPhase = "Scale"
)

const (
	ClusterReady     confv1beta1.ClusterStatus = "Ready"
	ClusterUnhealthy confv1beta1.ClusterStatus = "Unhealthy"
	ClusterUnknown   confv1beta1.ClusterStatus = "Unknown"
	ClusterChecking  confv1beta1.ClusterStatus = "Checking"

	ClusterPaused      confv1beta1.ClusterStatus = "Paused"
	ClusterPauseFailed confv1beta1.ClusterStatus = "PauseFailed"

	ClusterDryRun       confv1beta1.ClusterStatus = "DryRun"
	ClusterDryRunFailed confv1beta1.ClusterStatus = "DryRunFailed"

	ClusterInitializing         confv1beta1.ClusterStatus = "Initializing"
	ClusterInitializationFailed confv1beta1.ClusterStatus = "InitializationFailed"

	ClusterUpgrading     confv1beta1.ClusterStatus = "Upgrading"
	ClusterUpgradeFailed confv1beta1.ClusterStatus = "UpgradeFailed"

	ClusterMasterScalingUp   confv1beta1.ClusterStatus = "ScalingMasterNodesUp"
	ClusterMasterScalingDown confv1beta1.ClusterStatus = "ScalingMasterNodesDown"
	ClusterWorkerScalingUp   confv1beta1.ClusterStatus = "ScalingWorkerNodesUp"
	ClusterWorkerScalingDown confv1beta1.ClusterStatus = "ScalingWorkerNodesDown"
	ClusterScaleFailed       confv1beta1.ClusterStatus = "ScaleFailed"

	ClusterDeployingAddon    confv1beta1.ClusterStatus = "DeployingAddon"
	ClusterDeployAddonFailed confv1beta1.ClusterStatus = "DeployAddonFailed"

	ClusterManaging     confv1beta1.ClusterStatus = "Managing"
	ClusterManageFailed confv1beta1.ClusterStatus = "ManageFailed"

	ClusterDeleting     confv1beta1.ClusterStatus = "Deleting"
	ClusterDeleteFailed confv1beta1.ClusterStatus = "DeleteFailed"
)

const (
	PhaseSucceeded confv1beta1.BKEClusterPhaseStatus = "Succeeded"
	PhaseFailed    confv1beta1.BKEClusterPhaseStatus = "Failed"
	PhaseUnknown   confv1beta1.BKEClusterPhaseStatus = "Unknown"
	PhaseWaiting   confv1beta1.BKEClusterPhaseStatus = "Waiting"
	PhaseRunning   confv1beta1.BKEClusterPhaseStatus = "Running"
	PhaseSkipped   confv1beta1.BKEClusterPhaseStatus = "Skipped"
)

const (
	NodeUnknown confv1beta1.NodeStates = "Unknown"

	NodeInitializing confv1beta1.NodeStates = "Initializing"
	NodeInitFailed   confv1beta1.NodeStates = "InitFailed"

	NodeBootStrapping   confv1beta1.NodeStates = "BootStrapping"
	NodeBootStrapFailed confv1beta1.NodeStates = "BootStrapFailed"

	NodeDeleting     confv1beta1.NodeStates = "Deleting"
	NodeDeleteFailed confv1beta1.NodeStates = "DeleteFailed"

	NodeUpgrading     confv1beta1.NodeStates = "Upgrading"
	NodeUpgradeFailed confv1beta1.NodeStates = "UpgradeFailed"

	NodeReady    confv1beta1.NodeStates = "Ready"
	NodeNotReady confv1beta1.NodeStates = "NotReady"

	NodeManaging     confv1beta1.NodeStates = "Managing"
	NodeManageFailed confv1beta1.NodeStates = "ManageFailed"

	EtcdUpgrading     confv1beta1.NodeStates = "Upgrading"
	EtcdUpgradeFailed confv1beta1.NodeStates = "UpgradeFailed"
)

const (
	Deploying     confv1beta1.ClusterHealthState = "Deploying"
	DeployFailed  confv1beta1.ClusterHealthState = "DeployFailed"
	Upgrading     confv1beta1.ClusterHealthState = "Upgrading"
	UpgradeFailed confv1beta1.ClusterHealthState = "UpgradeFailed"
	Managing      confv1beta1.ClusterHealthState = "Managing"
	ManageFailed  confv1beta1.ClusterHealthState = "ManageFailed"
	Unhealthy     confv1beta1.ClusterHealthState = "Unhealthy"
	Healthy       confv1beta1.ClusterHealthState = "Healthy"
	Deleting      confv1beta1.ClusterHealthState = "Deleting"
)

const (
	NodeAgentPushedFlag = 1 << iota
	NodeAgentReadyFlag
	NodeEnvFlag
	NodeBootFlag
	NodeHAFlag
	MasterInitFlag
	NodeDeletingFlag
	NodeFailedFlag
	//NodeStateNeedRecord 这个code只是标记这个节点的状态需要在更新时进行记录，无其他作用，会在被记录后由statusManager移除
	NodeStateNeedRecord
)
